package com.zjdiepu.www.security.server.interceptor;


import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.zjdiepu.www.config.ServerConfig;
import com.zjdiepu.www.response.BaseResponse;
import com.zjdiepu.www.response.BooleanResponse;
import com.zjdiepu.www.security.base.enums.ResultCode;
import com.zjdiepu.www.security.server.core.Partners;
import com.zjdiepu.www.security.server.sign.ServerSignFactory;
import com.zjdiepu.www.security.sign.ICertificatelSignature;
import com.zjdiepu.www.security.sign.ISign;
import com.zjdiepu.www.security.sign.rsa.RsaProvider;
import com.zjdiepu.www.security.sign.rsa.RsaSign;

/**
 * 类描述: 签名拦截器 <br/>     
 * 项目名称:diepu-parent-partner <br/> 
 * 类名称:SignInterceptor <br/>     
 * 创建人:xiongxiaotun <br/> 
 * 创建时间:2017年8月15日 下午3:56:48  <br/>   
 * 修改人:xiongxiaotun <br/> 
 * 修改时间: 2017年8月15日 下午3:56:48   <br/>  
 * 修改备注:   <br/> 
 * @version V1.0   <br/>
 */
//@Aspect
//@Component
public class SignInterceptor {
	
	private Logger logger = LoggerFactory.getLogger(SignInterceptor.class);

    /**
     * 环绕通知需要携带ProceedingJoinPoint这个类型的参数
     * 环绕通知类似于动态代理的全过程 ProceedingJoinPoint类型的参数可以决定是否执行目标函数
     * 环绕通知必须有返回值
     *
     * @param proceedingJoinPoint
     * @return
     */
//    @Around(value = "@annotation(com.zjdiepu.www.partner.interceptor.PartnerProvider)")
//    @Around(value = "execution (public com.zjdiepu.www.*.api..*.*(..))")
    public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    	
    	boolean signSwitch = false;
    	boolean signResponseSwitch = false;
    	ISign sign_ = null;
    	String signSecretKey = null;
    	String saltOrSecretKey = null;
    	String signName = null;
    	String signCovenantKeyName = null;
    	Partners partner = PartnerHolder.getPartner();
    	if(partner != null) {
    		signSwitch = ServerConfig.getPartnerSignSwitch(partner);
    		signResponseSwitch = ServerConfig.getPartnerSignResponseSwitch(partner);
    		sign_ = ServerSignFactory.getSign(partner);
    		signSecretKey = ServerConfig.getPartnerSignSecretKey(partner);
    		saltOrSecretKey = ServerSignFactory.getSignSaltOrSecretKey(partner);
    		signName = ServerConfig.getPartnerSignName(partner);
    		signCovenantKeyName = ServerConfig.getPartnerSignCovenantKeyName(partner);
    	}
        Object[] objects = proceedingJoinPoint.getArgs();
       
        //请求验签
		if (signSwitch) {
			if (ArrayUtils.isNotEmpty(objects)) {
				Object request = objects[0];
				if (request instanceof ICertificatelSignature) {
					ICertificatelSignature signature = (ICertificatelSignature) request;
					String targetSign = signature.getSign();
					boolean isRsaResp = false;
					if(sign_ instanceof RsaSign) {
						targetSign = RsaProvider.deSignWithPri(targetSign, partner);
						isRsaResp = true;
					}
					logger.info("validate request sign :content is {}, sign is {}.", JSON.toJSONString(request), targetSign);
					if (!sign_.verifySign(request, targetSign, signSecretKey, saltOrSecretKey, signName, signCovenantKeyName)) {
						// 返回签名并加密结果
						BaseResponse<BooleanResponse> responseFail = BaseResponse
								.failWithBoolean(ResultCode.FAIL_SIGN_VALIDATE);
						BooleanResponse content = responseFail.getContent();
						content.setTimestamp(System.currentTimeMillis());
						content.setSign(sign_.generateSign(content, signSecretKey, saltOrSecretKey, signName, signCovenantKeyName, isRsaResp));
						return responseFail;
					}
					logger.info("validate request is success.");
				}
			}
		}

		Object proceed = proceedingJoinPoint.proceed();
		if(proceed instanceof BaseResponse) {
			BaseResponse<?> response = (BaseResponse<?>) proceed;
			
			//结果加签名
			if(signResponseSwitch) {
				boolean isRsaResp = false;
				if(sign_ instanceof RsaSign) {
					isRsaResp = true;
				}
				Object content = response.getContent();
				if (content instanceof ICertificatelSignature){
					ICertificatelSignature signature = (ICertificatelSignature) content;
					signature.setTimestamp(System.currentTimeMillis());
					signature.setSign(sign_.generateSign(content, signSecretKey, saltOrSecretKey, signName, signCovenantKeyName, isRsaResp));
					return response;
				}
			}
		}
        return proceed;
    }
}